/*******************************************************************************
 * Copyright (c) 2002 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.action;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sourceforge.perforce.core.PerforceCorePlugin;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.ICompositeSubmitResult;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.api.ISubmitResult;
import net.sourceforge.perforce.core.api.IWhereResult;
import net.sourceforge.perforce.core.internal.IWorkspaceHelper;
import net.sourceforge.perforce.core.internal.P4TeamProvider;
import net.sourceforge.perforce.core.internal.api.ChangeSpec;
import net.sourceforge.perforce.core.resources.IChangelist;
import net.sourceforge.perforce.ui.PerforceUIPlugin;
import net.sourceforge.perforce.ui.dialogs.ChangeSpecDialog;
import net.sourceforge.perforce.ui.internal.Policy;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.action.IAction;
import org.eclipse.team.core.TeamException;
import org.eclipse.ui.actions.WorkspaceModifyOperation;

/**
  * @version 	$Revision: 255 $
  * @author		<a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class SubmitAction extends PerforceAction
{
	// ------------------------------------------------------------------------------ Public Methods
	
	/** @see IActionDelegate#run(IAction) */
	public void run(IAction action)
	{
		final IChangelist[] changelists = getSelectedChangelists();				
		Policy.assertTrue(changelists.length == 1);
		
		ChangeSpecDialog dialog = null;
		try
		{
			String buttonText = Policy.bind("ChangeSpecDialog.okButtonTextSubmit");    //$NON-NLS-1$
			dialog = ChangeSpecDialog.newInstance(getShell(), changelists[0], buttonText);
		}
		catch (PerforceException e)
		{
			handle(e);
			return;
		}
		
		if (dialog.open() == ChangeSpecDialog.OK)
		{
			final ChangeSpec changeSpec = dialog.getChangeSpec();

			run(new WorkspaceModifyOperation()
			{
				protected void execute(IProgressMonitor monitor)
					throws CoreException, InvocationTargetException
				{
					monitor.beginTask("", 1000);
					monitor.setTaskName("Submitting changelist...");
					
					try
					{
						ICompositeSubmitResult compositeResult;
						try
						{
							IProgressMonitor subMonitor = Policy.subMonitorFor(monitor, 600);
							compositeResult = 
								changelists[0].getServer().submit(changeSpec, subMonitor);
						}
						catch (PerforceException e)
						{														
							throw new InvocationTargetException(e);
						}
						
						// Refresh Workspace
						ISubmitResult[] result = compositeResult.getResult();
						IProgressMonitor subMonitor = Policy.subMonitorFor(monitor, 100);
						subMonitor.beginTask("", result.length * 100);                 //$NON-NLS-1$
																							
						IWorkspaceHelper helper = PerforceCorePlugin.getWorkspaceHelper();
						List fileList = new ArrayList();
						for (int i = 0, length = result.length; i < length; i++)
						{
							IWhereResult whereResult =
								changelists[0].getServer().where(result[i].getDepotFilename());
								
							// Refresh local file
							final IFile[] workspaceFiles = 
								helper.findFilesForLocation(new Path(whereResult.getLocalFilename()));
							for (int j = 0; j < workspaceFiles.length; j++)
							{
								fileList.add(workspaceFiles[j]);								
								if (result[i].isRefreshed())
								{
									workspaceFiles[j].refreshLocal(
										IResource.DEPTH_ZERO, 
										subMonitor);
								}
							}
						}
						subMonitor.done();
						
						// Refresh Resource States
						IFile[] files = (IFile[]) fileList.toArray(new IFile[fileList.size()]);
						refreshResourceStates(files, Policy.subMonitorFor(monitor, 300));
						
						PerforceCorePlugin.getPlugin().broadcastChangelistChanges();
						
						
						// TODO: Open own dialog
						if (!compositeResult.getStatus().isOK())
						{
							throw new InvocationTargetException(
								new PerforceException(compositeResult.getStatus()));
						}
					}
					catch (PerforceException e)
					{
						throw new InvocationTargetException(e);
					}
					finally
					{
						monitor.done();
					}
				}
			}, PROGRESS_DIALOG);
		}
	}
	
	// --------------------------------------------------------------------------- Protected Methods

	/** @see TeamAction#isEnabled() */
	protected boolean isEnabled()
		throws PerforceException
	{
		IChangelist[] changelists = getSelectedChangelists();
		if (changelists.length != 1)
		{
			return false;
		}
			
		IPerforceServer server = changelists[0].getServer();
		if (!(server.getClient().equals(changelists[0].getClientName())))
		{
			return false;
		}
			
		return true;
	}
	
	// ----------------------------------------------------------------------------- Private Methods
	
	/** Returns an array of all selected IChangelist objects.
	  * 
	  * @return array of selected changelists. 
	  */
	private IChangelist[] getSelectedChangelists()
	{
		ArrayList resources = null;
		if (!getSelection().isEmpty())
		{
			resources = new ArrayList();
			for (Iterator elements = getSelection().iterator(); elements.hasNext();)
			{
				Object next = elements.next();
				
				if (next instanceof IChangelist)
				{
					resources.add(next);
					continue;
				}
				else
				if (next instanceof IAdaptable)
				{
					IAdaptable a = (IAdaptable) next;
					Object adapter = a.getAdapter(IChangelist.class);
					if (adapter instanceof IChangelist)
					{
						resources.add(adapter);
						continue;
					}
				}
			}
		}
		
		if (resources != null && !resources.isEmpty())
		{
			
			return (IChangelist[]) resources.toArray(new IChangelist[resources.size()]);
		}
		
		return new IChangelist[0];
	}
	
	/** Called to update the resource sync infos of the given resources.
	  *
	  * @param resources the changed resources.
	  * @param monitor the progress monitor. 
	  */
	private void refreshResourceStates(IResource[] resources, IProgressMonitor monitor) 
	{
		try
		{
			Map map = getProviderMapping(resources);
			Set keySet = map.keySet();
	
			for (Iterator it = keySet.iterator(); it.hasNext();)
			{
				P4TeamProvider provider = (P4TeamProvider) it.next();
				
				List list = (List) map.get(provider);						
				IResource[] providerResources = 
					(IResource[]) list.toArray(new IResource[list.size()]);
				provider.refreshState(providerResources, IResource.DEPTH_INFINITE, monitor);
			}
		}
		catch (TeamException e)
		{
			PerforceUIPlugin.log(e.getStatus());
		}
	}
}
